{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# PyGrid applied to Smart Cities and Smart Homes\n",
    "\n",
    "As we know, smart cities and smart homes are new concepts emerging on computer science field. Theses concepts aims to automate city/home services by data evaluation to take decisions based on local citizien behavior improving their life quality.\n",
    "\n",
    "One of these concepts that we can apply on our example purpose are [**Smart Grids**](https://www.smartgrid.gov/the_smart_grid/smart_grid.html).\n",
    "\n",
    "\n",
    "## Smart Grid\n",
    "&nbsp;The Smart Grid represents an unprecedented opportunity to move the energy industry into a new era of reliability, availability, and efficiency that will contribute to our economic and environmental health.The benefits associated with the Smart Grid include:\n",
    "\n",
    "- More efficient transmission of electricity\n",
    "- Quicker restoration of electricity after power disturbances\n",
    "- Reduced operations and management costs for utilities, and ultimately lower power costs for consumers\n",
    "- Reduced peak demand, which will also help lower electricity rates\n",
    "- Increased integration of large-scale renewable energy systems\n",
    "- Better integration of customer-owner power generation systems, including renewable energy systems\n",
    "- Improved security\n",
    "\n",
    "The Smart Grid will consist of millions of pieces and parts—controls, computers, power lines, and new technologies and equipment. One of the most important component on Smart Grid infrastructure are **Smart Meters**.\n",
    "\n",
    "#### Smart Meters\n",
    "&nbsp;Smart meters provide the Smart Grid interface between you and your energy provider. For instance, smart meters will deliver signals from your energy provider that can help you cut your energy costs. Smart meters also provide utilities with greater information about how much electricity is being used throughout their service areas.\n",
    "\n",
    "&nbsp;This energy information coming to and from your home through your smart meter can be run through a home energy management System (EMS), which will allow you to view it in an easy-to-understand format on your computer or hand-held device. A home EMS allows you to track your energy use in detail to better save energy. For instance, you can see the energy impact of various appliances and electronic products simply by monitoring your EMS while switching the devices on and off.\n",
    "\n",
    "&nbsp;An EMS also allows you to monitor real-time information and price signals from your utility and create settings to automatically use power when prices are lowest. You can also choose settings that allow specific appliances and equipment to turn off automatically when a large demand threatens to cause an outage—avoiding peak demand rates, helping to balance the energy load in your area, and preventing blackouts. Your utility may provide financial incentives for doing so.\n",
    "\n",
    "\n",
    "## Privacy Preserving problems\n",
    "As mentioned before, in the smart grid structure, smart meters send customer's data to the energy provider.It creates threats in user's privacy.  \n",
    "As argued in [Cyber Attack Impact on Critical Smart Grid Infrastructures](https://www.researchgate.net/publication/260301409_Cyber_Attack_Impact_on_Critical_Smart_Grid_Infrastructures): \n",
    "<em>\"The  basic  concern  about  consumer  threats  is  privacy \n",
    "violation. Sensitive consumer data such as name, address, and \n",
    "social security number, could be transmitted via Smart Meters \n",
    "which may be an attractive target for attackers. Smart Meters \n",
    "also  handle  consumers’  history,  information  depicting  their \n",
    "presence,  individual  preferences,  social  activities, \n",
    "consumption  habits,  as  well  as  health issues.  Such \n",
    "information could be exploited for various purposes, with the \n",
    "advertising case to seem the most innocent among others.\"</em>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## How can we apply PyGrid to solve this problem?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As mentioned in the previous tutorials, PyGrid nodes allow us to perform remote operations on datasets keeping them into their hosts. We can apply MPC operations to anonymize data during these operations, that way, the energy provider will get access to the aggregated values anonymized by thousands of users.\n",
    "\n",
    "We can replace default smart meters by Grid Nodes to preserve user's privacy."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<p align=\"center\">\n",
    "<img height=\"200px\" width=\"600px\" src=\"./images/smart_home.png\">\n",
    "</p>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "&nbsp; In this section, we'll learn how to **publish private dataset on your PyGrid node** and also, how **companies can use private data without get access to their values**.\n",
    "\n",
    "**NOTE:** At the time of running this notebook, we were running the grid components in background mode.  \n",
    "\n",
    "Components:\n",
    " - Smart PyGrid (http://localhost:5000)\n",
    " - Grid Node Bob's House ( ws://localhost:3000 )\n",
    " - Grid Node Alice's House ( ws://localhost:3001 )\n",
    " - Grid Node Bill's House ( ws://localhost:3002 )\n",
    " - Grid Node James' House ( ws://localhost:3003 )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setting Energy tariff using user's data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this fictional use case, we'll set energy tariff based on the usage of it. We'll measure the average energy spent by some houses (bob, alice and bill houses) to define a new value to the energy tariff.This measure will be made 4 times in a day."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1 - Customer\n",
    "\n",
    "As a customer, we need to register our grid node (smart meter or home assistant) on grid network. On top of that,  we  need to populate the node with energy spent in a certain time interval.\n",
    "\n",
    "1 - Register grid node on grid network <em>(This was done by starting the node)</em>.    \n",
    "2 - Populate node.  \n",
    "PS: **Each customer needs to populate their own nodes with energy spent by home appliances, or receive it by an energy meter that lives on customer's house**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Import dependencies"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import syft as sy\n",
    "import torch as th\n",
    "from syft.grid.clients.data_centric_fl_client import DataCentricFLClient\n",
    "\n",
    "hook = sy.TorchHook(th)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Bob's House"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob_home_assistant = DataCentricFLClient(hook, \"ws://localhost:3000\")\n",
    "\n",
    "# smart light bulb\n",
    "lb_energy_data_chunk = th.tensor([ 5.0, 8.5, 9.7, 2.5]).tag(\"#energy-consumption\", \"#light-bulb\").describe(\"light bulb energy consumption(Kwatts)\")\n",
    "\n",
    "# smart coffe pot\n",
    "coffe_energy_data_chunk = th.tensor([2.5, 3.7, 1.2, 1.0]).tag(\"#energy-consumption\", \"#coffe-pot\").describe(\"coffe pot energy consumption(Kwatts)\")\n",
    "\n",
    "# smart fridge\n",
    "fridge_energy_data_chunk = th.tensor([8.0, 4.9, 7, 10.9]).tag(\"#energy-consumption\", \"#fridge\").describe(\"Fridge energy consumption(Kwatts)\")\n",
    "\n",
    "\n",
    "# Sending to home assistant\n",
    "lb_energy_data_chunk.send(bob_home_assistant, garbage_collect_data=False)\n",
    "coffe_energy_data_chunk.send(bob_home_assistant, garbage_collect_data=False)\n",
    "fridge_energy_data_chunk.send(bob_home_assistant, garbage_collect_data=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Alice's House"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "alice_home_assistant = DataCentricFLClient(hook, \"ws://localhost:3001\")\n",
    "\n",
    "# smart light bulb\n",
    "lb_energy_data_chunk = th.tensor([ 3.0, 2.5, 6.7, 4.5]).tag(\"#energy-consumption\", \"#light-bulb\").describe(\"light bulb energy consumption(Kwatts)\")\n",
    "\n",
    "# smart coffe pot\n",
    "coffe_energy_data_chunk = th.tensor([0.5, 1.7, 5.2, 1.0]).tag(\"#energy-consumption\", \"#coffe-pot\").describe(\"coffe pot energy consumption(Kwatts)\")\n",
    "\n",
    "# smartfridge\n",
    "fridge_energy_data_chunk = th.tensor([3.0, 4.9, 8, 5.9]).tag(\"#energy-consumption\", \"#fridge\").describe(\"Fridge energy consumption(Kwatts)\")\n",
    "\n",
    "\n",
    "# Sending to home assistant\n",
    "lb_energy_data_chunk.send(alice_home_assistant , garbage_collect_data=False)\n",
    "coffe_energy_data_chunk.send(alice_home_assistant , garbage_collect_data=False)\n",
    "fridge_energy_data_chunk.send(alice_home_assistant, garbage_collect_data=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Bill's House"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bill_home_assistant = DataCentricFLClient(hook, \"ws://localhost:3002\")\n",
    "\n",
    "# smart light bulb\n",
    "lb_energy_data_chunk = th.tensor([ 8.0, 7.5, 9.7, 2.5]).tag(\"#energy-consumption\", \"#light-bulb\").describe(\"light bulb energy consumption(Kwatts)\")\n",
    "\n",
    "# smartfridge\n",
    "fridge_energy_data_chunk = th.tensor([3.7, 4.3, 8, 5.9]).tag(\"#energy-consumption\", \"#fridge\").describe(\"Fridge energy consumption(Kwatts)\")\n",
    "\n",
    "# Sending to home assistant\n",
    "lb_energy_data_chunk.send(bill_home_assistant, garbage_collect_data=False)\n",
    "fridge_energy_data_chunk.send(bill_home_assistant, garbage_collect_data=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2 - Energy Provider (Company)\n",
    "\n",
    "As a company, we need to search by all nodes registered on the smart grid <em>(grid network)</em> asking for their energy spents.\n",
    "\n",
    "PS: It's important to note that **we must not be able to retrieve their data**, otherwise someone would be able to get this data and apply statistical tools to discover customers ' habits by patterns found on the usage of home appliances. Therefore, all arithmetic operations should be made remotelly."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Using Grid Network as a Smart Grid"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_smart_grid = sy.PublicGridNetwork(hook, \"http://localhost:5000\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Querying user's data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Energy spent with fridge\n",
    "results = my_smart_grid.search(\"#energy-consumption\")\n",
    "print(\"Results: \", results)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3 - Get energy expenditure average"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from functools import reduce\n",
    "\n",
    "def sum_energy_spent_by_home(home_id, query_dict):\n",
    "    # It will aggregate home appliances' spent remotelly.\n",
    "    # Example: If we have light-bulb and fridge at the same house, we need to aggregate it on the user's device.\n",
    "    return reduce(lambda x,y: x + y, query_dict[home_id])\n",
    "\n",
    "def smart_city_aggregation(x,y):\n",
    "    print(\"Sending X(\", x.location, \") to Y(\", y.location, \").\")\n",
    "    x.location.connect_nodes(y.location)\n",
    "    return x.move(y.location) + y\n",
    "\n",
    "energy_spent_by_houses = [ sum_energy_spent_by_home(home_id, results) for home_id in results.keys() ]\n",
    "total_spend = reduce(lambda x, y: smart_city_aggregation(x,y), energy_spent_by_houses)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "p_average = total_spend / 3 # Total spent divided by number of houses"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4 - Defining Energy tariff by energy expenditure average\n",
    "Now we can recover the value of the energy average because it has been anonymized by the aggregation. A malicious agent won't be able to extract a piece of information about any specific customer.\n",
    "\n",
    "PS: **We're using an array to represent energy spent at different times of the day. (6 hours between each measure)**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "average = p_average.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Calculating energy tariff\n",
    "Our function to update energy tariff is pretty simple."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def update_tariff(energy_average):\n",
    "    energy_coefficient = 0.5\n",
    "    energy_constant = 5\n",
    "    return energy_average * energy_coefficient + energy_constant"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "energy_tariff = th.stack(list(map(lambda x: update_tariff(x), average)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "energy_tariff"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4 - Conclusion"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "&nbsp; With the new regulation such as [GDPR](https://eugdpr.org/), enterprises are under pressure to have less freedom with how they use - and more importantly how they analyze - personal information. However, as we can see in this example,companies can use aggregated/anonymized values to keep improving their services without use customers' data directly."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Congratulations!!! - Time to Join the Community!\n",
    "\n",
    "Congratulations on completing this notebook tutorial! If you enjoyed this and would like to join the movement toward privacy preserving, decentralized ownership of AI and the AI supply chain (data), you can do so in the following ways!\n",
    "\n",
    "### Star PySyft on GitHub\n",
    "\n",
    "The easiest way to help our community is just by starring the GitHub repos! This helps raise awareness of the cool tools we're building.\n",
    "\n",
    "- [Star PySyft](https://github.com/OpenMined/PySyft)\n",
    "\n",
    "### Join our Slack!\n",
    "\n",
    "The best way to keep up to date on the latest advancements is to join our community! You can do so by filling out the form at [http://slack.openmined.org](http://slack.openmined.org)\n",
    "\n",
    "### Join a Code Project!\n",
    "\n",
    "The best way to contribute to our community is to become a code contributor! At any time you can go to PySyft GitHub Issues page and filter for \"Projects\". This will show you all the top level Tickets giving an overview of what projects you can join! If you don't want to join a project, but you would like to do a bit of coding, you can also look for more \"one off\" mini-projects by searching for GitHub issues marked \"good first issue\".\n",
    "\n",
    "- [PySyft Projects](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3AProject)\n",
    "- [Good First Issue Tickets](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
    "\n",
    "### Donate\n",
    "\n",
    "If you don't have time to contribute to our codebase, but would still like to lend support, you can also become a Backer on our Open Collective. All donations go toward our web hosting and other community expenses such as hackathons and meetups!\n",
    "\n",
    "[OpenMined's Open Collective Page](https://opencollective.com/openmined)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
